﻿namespace Extensions.Web.UI
{
    using Extensions.Web.ViewModel;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq.Expressions;
    using System.Reflection;
    using System.Web.UI;

    [ParseChildren(true, "EventTriggers")]
    public abstract class BehaviorControl<T> : UserControl where T: EventTriggerControl
    {
        private List<T> eventTriggers;
        private Finder<T> targetFinder;

        protected BehaviorControl()
        {
            this.eventTriggers = new List<T>();
            this.targetFinder = null;
        }

        private void AttachSourceEvent(Control control, string eventName)
        {
            EventDescriptor entryEventDescriptor = MemberUtility.GetEntryEventDescriptor(control.GetType(), eventName);
            MethodInfo method = entryEventDescriptor.ComponentType.GetEvent(entryEventDescriptor.Name).EventHandlerType.GetMethod("Invoke");
            Delegate delegate2 = this.GetEventLambdaExpressionDelegate(entryEventDescriptor.EventType, control, method);
            entryEventDescriptor.AddEventHandler(control, delegate2);
        }

        private Delegate GetEventLambdaExpressionDelegate(Type eventType, Control control, MethodInfo methodInfo)
        {
            BlockExpression expression4;
            ConstantExpression instance = Expression.Constant(this);
            ConstantExpression expression2 = Expression.Constant(control);
            MethodCallExpression expression3 = Expression.Call(instance, typeof(BehaviorControl<T>).GetMethod("Invoke", BindingFlags.NonPublic | BindingFlags.Instance), new Expression[] { expression2 });
            ParameterInfo[] parameters = methodInfo.GetParameters();
            ParameterExpression[] expressionArray = new ParameterExpression[parameters.Length];
            for (int i = 0; i < parameters.Length; i++)
            {
                expressionArray[i] = Expression.Parameter(parameters[i].ParameterType, parameters[i].Name);
            }
            if (methodInfo.ReturnType.ToString() == "System.Void")
            {
                expression4 = Expression.Block(new Expression[] { expression3 });
            }
            else
            {
                DefaultExpression expression5 = Expression.Default(methodInfo.ReturnType);
                expression4 = Expression.Block(methodInfo.ReturnType, new Expression[] { expression3, expression5 });
            }
            return Expression.Lambda(eventType, expression4, expressionArray).Compile();
        }

        private void Invoke(Control control)
        {
            this.OnTrigger(this, new EventTriggerEventArgs<T>(control));
        }

        protected virtual void OnAttached(object sender, EventArgs e)
        {
        }

        protected override void OnInit(EventArgs e)
        {
            if (this.TargetFinder.Control != null)
            {
                foreach (EventTriggerControl control in this.EventTriggers)
                {
                    Finder<T> finder = new Finder<T>(this, control.SourceControlID, control.SourceControlType);
                    if (finder.Control != null)
                    {
                        this.AttachSourceEvent(finder.Control, control.EventName);
                        this.OnAttached(finder.Control, new EventArgs());
                    }
                }
            }
            base.OnInit(e);
        }

        protected virtual void OnTrigger(object sender, EventTriggerEventArgs<T> e)
        {
        }

        [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
        public List<T> EventTriggers
        {
            get
            {
                return this.eventTriggers;
            }
        }

        public string TargetControlID
        {
            get
            {
                return ((this.ViewState["TargetControlID"] != null) ? this.ViewState["TargetControlID"].ToString() : "");
            }
            set
            {
                this.ViewState["TargetControlID"] = value;
            }
        }

        public string TargetControlType
        {
            get
            {
                return ((this.ViewState["TargetControlType"] != null) ? this.ViewState["TargetControlType"].ToString() : "");
            }
            set
            {
                this.ViewState["TargetControlType"] = value;
            }
        }

        protected Finder<T> TargetFinder
        {
            get
            {
                if (this.targetFinder == null)
                {
                    this.targetFinder = new Finder<T>(this, this.TargetControlID, this.TargetControlType);
                }
                return this.targetFinder;
            }
        }

        public class EventTriggerEventArgs : EventArgs
        {
            private Control _triggerControl;

            public EventTriggerEventArgs(Control control)
            {
                this._triggerControl = control;
            }

            public Control TriggerControl
            {
                get
                {
                    return this._triggerControl;
                }
            }
        }

        protected class Finder
        {
            private System.Web.UI.Control _control;
            private string _controlID;
            private string _controlType;

            public Finder(System.Web.UI.Control control, string controlID, string controlType)
            {
                this._control = control;
                this._controlID = controlID;
                this._controlType = controlType;
            }

            private static System.Web.UI.Control DataBoundControlHelperFindControlByType(System.Web.UI.Control control, string containerType)
            {
                for (System.Web.UI.Control control2 = control.Parent; control2.Parent != null; control2 = control2.Parent)
                {
                    string str = control2.GetType().ToString();
                    if (str.Contains("."))
                    {
                        str = str.Substring(str.LastIndexOf(".") + 1);
                    }
                    if (str == containerType)
                    {
                        return control2;
                    }
                }
                return null;
            }

            public System.Web.UI.Control Control
            {
                get
                {
                    if (this._control != null)
                    {
                        if (this._controlID != "")
                        {
                            return UserControl.DataBoundControlHelperFindControl(this._control, this._controlID);
                        }
                        if (this._controlType != "")
                        {
                            return BehaviorControl<T>.Finder.DataBoundControlHelperFindControlByType(this._control, this._controlType);
                        }
                    }
                    return null;
                }
            }
        }
    }
}

